Skip to main content

01 起源

编程范式(Programming Paradigm)指从事软件工程的一类典型的编程风格。通过了解编程语言的范式,能加深对编程语言的认识,提高自己的编程技能,写出更好的代码。

C 语言

  1. 静态弱类型语言,使用变量时需要声明变量类型,但类型间可以有隐式转换;
  2. 不同的变量类型可以用结构体(struct)组合在一起,声明新的数据类型;
  3. 可以用 typedef 关键字定义类型的别名,达到变量类型的抽象;
  4. 有结构化程序设计、具有变量作用域以及递归功能的过程式语言;
  5. 传递参数一般是以值传递,也可以传递指针;
  6. 通过指针可以容易地对内存进行低级控制,同时也加大了编程复杂度;
  7. 编译预处理让语言的编译更具有弹性(跨平台)。

程序员可以在微观层面写出非常精细和精确的编程操作,可以在底层和系统细节上非常自由、灵活和精准地控制代码。但在代码组织和功能编程上不占优势。

void swap(int* x, int* y)
{
int tmp = *x;
*x = *y;
*y = tmp;
}

要达到调用完函数后,实参内容的交换,必须要把实参的地址(即指针)传递进来。但该函数只能给 int 值用。

编译器会使用一切方式来做类型转换,类型转换有时候可以让编程更方便一些,也让相近的类型可以做到一点点的泛型。但类型转换会出很多问题。double 型的或 long 型 64 位的类型强转成 int,会导致程序的步长不一样。

C 语言的泛型

swap 函数

void swap(void* x, void* y, size_t size)
{
char tmp[size];
memcpy(tmp, y, size);
memcpy(y, x, size);
memcpy(x, tmp, size);
}
  • 增加 size 参数:用了 void* 后类型被抽象掉了,编译器不能通过类型得到类型的尺寸,需要手动地加上一个类型长度的标识;
  • 使用 memcpy() 函数:类型被抽象掉了,有可能传进来的参数类型是一个结构体,不能用赋值表达式,为了交换复杂类型的值,只能使用内存复制的方法;
  • temp[size] 数组:交换数据时需要用的 buffer,用 buffer 来做临时的空间存储。
#define swap(x, y, size) {\
char temp[size]; \
memcpy(temp, &y, size); \
memcpy(&y, &x, size); \
memcpy(&x, temp, size); \
}

编译器做字符串替换,会导致代码膨胀,编译出的执行文件比较大。

无法检查传入参数的size,增加接口复杂度。

Search 函数

int search(int* a, size_t size, int target) {
for(int i=0; i<size; i++) {
if (a[i] == target) {
return i;
}
}
return -1;
}
int search(void* a, size_t size, void* target, 
size_t elem_size, int(*cmpFn)(void*, void*) )
{
for(int i=0; i<size; i++) {
// why not use memcmp()
// use unsigned char * to calculate the address
if ( cmpFn ((unsigned char *)a + elem_size * i, target) == 0 ) {
return i;
}
}
return -1;
}

  1. elem_size:数组里面每个元素的 size;
  2. cmpFn:比较数组里的每个元素和target是否相等。

调用者需要提供如下的比较函数:


int int_cmp(int* x, int* y)
{
return *x - *y;
}

int string_cmp(char* x, char* y){
return strcmp(x, y);
}

// 有业务类型的结构体
...